/*!
redis 连接帮助模块
包括连接器
相关的操作方法
*/
use lazy_static;

use anyhow::Error;
use redis::{cmd, Client, Commands, Connection, RedisResult, Value};
use std::collections::HashMap;
use std::option::Option::Some;
use std::result::Result::Ok;
use std::sync::Mutex;
lazy_static! {
    /// 定义全局的redis 配置
    ///
    /// Example:
    ///
    /// ```no_run,rust
    /// match REDIS.lock() {
    ///     Ok(mut cfg) => {
    ///         if let Some(_) = cfg.connect() {
    ///             true
    ///         } else {
    ///             false
    ///         }
    ///     }
    ///     _ => false,
    ///  }
    /// ```
    pub static ref REDIS: Mutex<RedisConfig> = Mutex::new(RedisConfig::new());
}

/// 连接定义
pub trait Connector {
    /// 获取连接客户端
    fn client(&mut self) -> Option<Client>;
    /// 获取连接
    fn connect(&mut self) -> Option<Connection>;
}

/// 连接配置对象
#[derive(Debug)]
pub struct RedisConfig {
    ///连接地址
    address: String,
    ///连接端口
    port: String,
    ///连接密码
    password: String,
    ///连接用户名
    username: String,
    ///连接数据库
    db: String,
}

impl RedisConfig {
    pub fn new() -> RedisConfig {
        RedisConfig {
            address: format!(""),
            port: format!(""),
            password: format!(""),
            username: format!(""),
            db: format!(""),
        }
    }

    pub fn set(&mut self, address: &str, port: &str, db: &str, password: &str, username: &str) {
        self.set_address(address);
        self.set_port(port);
        self.set_db(db);
        self.set_username(username);
        self.set_password(password);
    }

    pub fn set_address(&mut self, para: &str) {
        self.address = para.into();
    }

    pub fn set_port(&mut self, para: &str) {
        self.port = para.into();
    }

    pub fn set_db(&mut self, para: &str) {
        self.db = para.into();
    }

    pub fn set_username(&mut self, para: &str) {
        self.username = para.into();
    }

    pub fn set_password(&mut self, para: &str) {
        self.password = para.into();
    }

    fn parse_conn_info(&mut self) -> redis::ConnectionInfo {
        let username = if self.username == "" {
            None
        } else {
            Some((&self.username).parse().unwrap_or(String::new()))
        };
        let password = if self.password == "" {
            None
        } else {
            Some((&self.password).parse().unwrap_or(String::new()))
        };
        redis::ConnectionInfo {
            addr: redis::ConnectionAddr::Tcp(
                (&self.address).parse().unwrap_or(format!("127.0.0.1")),
                (&self.port).parse().unwrap_or(6379 as u16),
            ),
            redis: redis::RedisConnectionInfo {
                db: (&self.db).parse().unwrap_or(0),
                username,
                password,
            },
        }
    }
}

impl Connector for RedisConfig {
    fn client(&mut self) -> Option<Client> {
        match Client::open(self.parse_conn_info()) {
            Ok(client) => Some(client),
            Err(_) => None,
        }
    }
    fn connect(&mut self) -> Option<Connection> {
        match Client::open(self.parse_conn_info()) {
            Ok(client) => {
                if let Ok(conn) = client.get_connection() {
                    Some(conn)
                } else {
                    None
                }
            }
            Err(_) => None,
        }
    }
}

/// 执行redis命令的闭包方法
///
/// example
///
/// ```no_run,rust
/// exec(move |conn| {
///     let res = redis::cmd("get")
///     .arg("test")
///     .query::<redis::Value>(conn);
///     println1("{:?}",res);
/// })
/// ```
pub fn exec<F>(func: F) -> sciter::Value
where
    F: FnOnce(&mut Connection) -> Result<sciter::Value, Error>,
{
    fn format(code: i32, data: sciter::Value, msg: String) -> sciter::Value {
        vmap! {
            "code"=> code,
            "data" => data,
            "msg" => msg
        }
    }
    match REDIS.lock() {
        Ok(mut r) => match r.connect() {
            Some(mut conn) => match func(&mut conn) {
                Ok(data) => format(200, data, "请求成功".to_string()),
                Err(err) => format(500, sciter::Value::null(), format!("{}", err)),
            },
            None => format(
                500,
                sciter::Value::null(),
                format!("{}", "获取redis连接失败!"),
            ),
        },
        Err(err) => format(500, sciter::Value::null(), format!("{}", err)),
    }
}

/// 连接redis
pub fn connect_redis(
    address: String,
    port: String,
    db: String,
    password: String,
    username: String,
) -> bool {
    match REDIS.lock() {
        Ok(mut cfg) => {
            cfg.set(&address, &port, &db, &password, &username);
            if let Some(_) = cfg.connect() {
                true
            } else {
                false
            }
        }
        _ => false,
    }
}

/// 获取db个数
pub fn get_db() -> HashMap<String, String> {
    match REDIS.lock() {
        Ok(mut r) => {
            if let Some(mut conn) = r.connect() {
                let res = cmd("config")
                    .arg("get")
                    .arg("databases")
                    .query::<HashMap<String, String>>(&mut conn);
                return match res {
                    Ok(res) => res,
                    _ => HashMap::new(),
                };
            }
            HashMap::new()
        }
        _ => HashMap::new(),
    }
}

/// 获取所有的key
pub fn get_keys(condition: String) -> sciter::Value {
    exec(|conn| {
        let mut cursor = format!("-1");
        let mut arr = varray![];
        while cursor != "0" {
            if cursor == "-1" {
                cursor = format!("0");
            }
            let res = cmd("scan")
                .arg(&cursor)
                .arg("match")
                .arg(&condition)
                .arg("count")
                .arg("500")
                .query::<Value>(conn)?;
            match res {
                Value::Bulk(res) => {
                    for item in res {
                        match item {
                            Value::Data(data) => {
                                cursor = String::from_utf8(data).unwrap_or(format!("0"))
                            }
                            Value::Bulk(res) => {
                                for item in res {
                                    match item {
                                        Value::Data(data) => {
                                            arr.push(String::from_utf8(data).unwrap_or(format!("")))
                                        }
                                        _ => {}
                                    }
                                }
                            }
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
        }
        Ok(arr)
    })
}

/// 获取键的信息
pub fn get_infos(key: String, version: i32) -> String {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if version > 3 {
                    let res = redis::pipe()
                        .cmd("type")
                        .arg(&key)
                        .cmd("memory")
                        .arg("usage")
                        .arg(&key)
                        .cmd("pttl")
                        .arg(&key)
                        .query::<(String, i32, i32)>(&mut conn);
                    return match res {
                        Ok(res) => {
                            format!("{},{},{}", res.0, res.1, res.2)
                        }
                        Err(err) => {
                            println!("null {}", err);
                            format!(",,")
                        }
                    };
                } else {
                    let res = redis::pipe()
                        .cmd("type")
                        .arg(&key)
                        .cmd("pttl")
                        .arg(&key)
                        .query::<(String, i32)>(&mut conn);
                    if let Ok(r) = res {
                        format!("{},{},{}", r.0, '0', r.1)
                    } else {
                        format!(",,")
                    }
                }
            } else {
                format!(",,")
            }
        }
        Err(_) => return format!(",,"),
    }
}

///删除key
pub fn delete_key(key: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(res) = redis::cmd("del").arg(&key).query::<bool>(&mut conn) {
                    res
                } else {
                    false
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// key是否存在
pub fn key_exist(key: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                match redis::cmd("exists").arg(&key).query::<bool>(&mut conn) {
                    Ok(res) => res,
                    Err(err) => {
                        println!("{}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 添加string类型的key
pub fn add_string_key(key: String, value: String, time: String, time_type: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if time.as_str() != "" {
                    match time_type.as_str() {
                        "2" => {
                            if let Ok(res) = redis::cmd("set")
                                .arg(&key)
                                .arg(&value)
                                .arg("px")
                                .arg(&time)
                                .query::<bool>(&mut conn)
                            {
                                res
                            } else {
                                false
                            }
                        }
                        _ => {
                            if let Ok(res) = redis::cmd("set")
                                .arg(&key)
                                .arg(&value)
                                .arg("ex")
                                .arg(&time)
                                .query::<bool>(&mut conn)
                            {
                                res
                            } else {
                                false
                            }
                        }
                    }
                } else {
                    match redis::cmd("set")
                        .arg(&key)
                        .arg(&value)
                        .query::<bool>(&mut conn)
                    {
                        Ok(res) => res,
                        Err(err) => {
                            println!("{}", err);
                            false
                        }
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 重命名key
pub fn rename_key(o_key: String, n_key: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(res) = redis::cmd("rename")
                    .arg(&o_key)
                    .arg(&n_key)
                    .query::<bool>(&mut conn)
                {
                    res
                } else {
                    false
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 设置key过期时间
pub fn set_key_expire(key: String, t: String, time: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if time.as_str() == "-1" {
                    return if let Ok(res) = redis::cmd("persist").arg(&key).query::<bool>(&mut conn)
                    {
                        res
                    } else {
                        false
                    };
                }
                match t.as_str() {
                    "2" => {
                        if let Ok(res) = redis::cmd("pexpire")
                            .arg(&key)
                            .arg(&time)
                            .query::<bool>(&mut conn)
                        {
                            res
                        } else {
                            false
                        }
                    }
                    _ => {
                        if let Ok(res) = redis::cmd("expire")
                            .arg(&key)
                            .arg(&time)
                            .query::<bool>(&mut conn)
                        {
                            res
                        } else {
                            false
                        }
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 获取string类型的数据
pub fn get_string_val(key: String) -> Option<String> {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = conn.get(key).unwrap_or(redis::Value::Nil);
                match res {
                    Value::Data(data) => {
                        let res =
                            String::from_utf8(data).unwrap_or("二进制文件，无法显示！".to_string());
                        Some(res)
                    }
                    _ => Some("不是字符串数据！".to_string()),
                }
            } else {
                Some("不是字符串数据！".to_string())
            }
        }
        Err(_) => None,
    }
}

/// 获取list类型的数据
pub fn get_list_val(key: String, page: usize, range: usize) -> sciter::Value {
    let mut list = varray![];
    exec(|conn| {
        let total: i32 = conn.llen(&key)?;
        let max = (total as f32 / range as f32).ceil() as usize;
        let min = 1 as usize;
        let mut current_page = page;
        if page < min {
            current_page = min;
        }
        if page > max {
            current_page = max;
        }

        let start = (current_page - 1) * range;
        let end = current_page * range;
        let res: Value = conn.lrange(&key, start as isize, end as isize)?;
        match res {
            Value::Bulk(res) => {
                for item in res {
                    match item {
                        Value::Data(data) => {
                            if let Ok(val) = String::from_utf8(data) {
                                list.push(val);
                            };
                        }
                        _ => {}
                    }
                }
            }
            _ => {}
        }
        Ok(vmap! {
            "total" => total,
            "list" => list,
            "current" => sciter::Value::from(current_page as i32),
            "size" => sciter::Value::from(range as i32)
        })
    })
}

/// 修改list类型的值
pub fn set_list_index_val(key: String, index: i32, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = redis::cmd("lset")
                    .arg(&key)
                    .arg(index)
                    .arg(value)
                    .query::<bool>(&mut conn);
                match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("{}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 删除list中的某一个值
pub fn delete_list_index_val(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(max) = cmd("llen").arg(&key).query::<i32>(&mut conn) {
                    if max == 1 {
                        return false;
                    }
                }
                let res = redis::cmd("lrem")
                    .arg(&key)
                    .arg("1")
                    .arg(value)
                    .query::<bool>(&mut conn);
                match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("{}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 将一个值插入到已存在的列表
pub fn append_list_val(key: String, t: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                match t.as_str() {
                    "r" => {
                        let res = redis::cmd("rpushx")
                            .arg(&key)
                            .arg(&value)
                            .query::<bool>(&mut conn);
                        match res {
                            Ok(_) => true,
                            Err(err) => {
                                println!("redis_helper.rs line 473 err: {}", err);
                                false
                            }
                        }
                    }
                    _ => {
                        let res = redis::cmd("lpushx")
                            .arg(&key)
                            .arg(&value)
                            .query::<bool>(&mut conn);
                        match res {
                            Ok(_) => true,
                            Err(err) => {
                                println!("redis_helper.rs line 486 err: {}", err);
                                false
                            }
                        }
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 裁剪一个list
pub fn clip_list(key: String, start: i32, end: i32) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if start > end {
                    return false;
                }
                if let Ok(max) = cmd("llen").arg(&key).query::<i32>(&mut conn) {
                    if end > max {
                        return false;
                    }
                }
                let res = cmd("ltrim")
                    .arg(&key)
                    .arg(&start)
                    .arg(&end)
                    .query::<bool>(&mut conn);
                match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 514 err: {}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 查询hash的数据
pub fn get_hash_data(key: String, pattern: String) -> sciter::Value {
    exec(move |conn| {
        let mut cursor = format!("-1");
        let mut arr = varray![];
        while cursor != "0" {
            let mut keys = vec![];
            let mut values = vec![];
            if cursor == "-1" {
                cursor = format!("0")
            }
            let res = cmd("hscan")
                .arg(&key)
                .arg(&cursor)
                .arg("match")
                .arg(&pattern)
                .arg("count")
                .arg("500")
                .query::<Value>(conn)?;
            match res {
                Value::Bulk(res) => {
                    for item in res {
                        match item {
                            Value::Data(data) => {
                                cursor = String::from_utf8(data).unwrap_or(format!("0"));
                            }
                            Value::Bulk(res) => {
                                for (i, v) in res.iter().enumerate() {
                                    match v {
                                        Value::Data(data) => {
                                            let str = String::from_utf8(data.to_owned())
                                                .unwrap_or(format!(""));
                                            if i % 2 == 0 {
                                                keys.push(str);
                                            } else {
                                                values.push(str);
                                            }
                                        }
                                        _ => {}
                                    }
                                }
                            }
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
            for (i, k) in keys.iter().enumerate().to_owned() {
                if let Some(val) = values.get(i) {
                    arr.push(vmap! {
                        "key" => k,
                         "value" => val
                    })
                }
            }
        }
        Ok(arr)
    })
}
/// 查询hash字段是否存在
pub fn hash_field_exist(key: String, field: String) -> sciter::Value {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res: RedisResult<bool> = conn.hexists(&key, &field);
                return match res {
                    Ok(res) => sciter::Value::from(res),
                    Err(_) => sciter::Value::from(false),
                };
            }
            sciter::Value::from(false)
        }
        Err(_e) => sciter::Value::null(),
    }
}
/// 修改hash的值
pub fn edit_hash_data(key: String, field: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("hset")
                    .arg(&key)
                    .arg(&field)
                    .arg(&value)
                    .query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 586 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// 插入键值
pub fn append_hash_data(key: String, field: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("hmset")
                    .arg(&key)
                    .arg(&field)
                    .arg(&value)
                    .query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 612 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}
/// 删除hash值
pub fn delete_hash_data(key: String, field: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("hdel").arg(&key).arg(&field).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 824 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}
///获取set数据
pub fn get_set_data(key: String, pattern: String) -> sciter::Value {
    exec(|conn| {
        let mut cursor = "-1".to_string();
        let mut arr = varray![];
        while cursor != "0" {
            if cursor == "-1" {
                cursor = "0".to_string();
            }
            let res = cmd("sscan")
                .arg(&key)
                .arg(&cursor)
                .arg("match")
                .arg(&pattern)
                .arg("count")
                .arg("500")
                .query::<Value>(conn)?;
            match res {
                Value::Bulk(res) => {
                    for item in res {
                        match item {
                            Value::Data(data) => {
                                cursor = String::from_utf8(data).unwrap_or(format!("0"));
                            }
                            Value::Bulk(res) => {
                                for item in res {
                                    match item {
                                        Value::Data(data) => {
                                            arr.push(
                                                String::from_utf8(data).unwrap_or(format!("")),
                                            );
                                        }
                                        _ => {}
                                    }
                                }
                            }
                            _ => {}
                        }
                    }
                }
                _ => {}
            };
        }
        Ok(arr)
    })
}
/// 添加一个set数据
pub fn append_set_val(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("sadd").arg(&key).arg(&value).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 863 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// 删除一个值
pub fn delete_set_val(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("srem").arg(&key).arg(&value).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 883 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// 添加list key 类型数据
pub fn add_list_key(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("lpush").arg(&key).arg(&value).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 710 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// zset 结果显示
pub fn z_set_list(key: String, pattern: String) -> sciter::Value {
    exec(|conn| {
        let mut start = "-1".to_string();
        let mut arr = varray![];
        let mut keys = vec![];
        let mut values = vec![];
        while start != "0" {
            if start == "-1" {
                start = "0".to_string();
            }
            let res = cmd("zscan")
                .arg(&key)
                .arg(&start)
                .arg("match")
                .arg(&pattern)
                .arg("count")
                .arg("500")
                .query::<Value>(conn)?;
            match res {
                Value::Bulk(res) => {
                    for item in res {
                        match item {
                            Value::Data(data) => {
                                start = String::from_utf8(data).unwrap_or(format!("0"));
                            }
                            Value::Bulk(val) => {
                                for (index, item) in val.iter().enumerate() {
                                    match item {
                                        Value::Data(data) => {
                                            let str = String::from_utf8(data.to_owned())
                                                .unwrap_or(format!(""));
                                            if index % 2 == 0 {
                                                keys.push(str)
                                            } else {
                                                values.push(str)
                                            }
                                        }
                                        _ => {}
                                    }
                                }
                                for (i, k) in keys.iter().enumerate() {
                                    if let Some(val) = values.get(i) {
                                        arr.push(vmap! {
                                            "key" => k.to_string(),
                                             "value" => val.to_string()
                                        })
                                    }
                                }
                            }
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
        }
        Ok(arr)
    })
}
/// 判断member是否存在
pub fn field_is_exist(key: String, field: String) -> sciter::Value {
    exec(move |conn| {
        let res: bool = conn.zrank(key, field)?;
        Ok(sciter::Value::from(res))
    })
}
/// 插入member
pub fn append_z_set_data(key: String, field: String, value: String) -> sciter::Value {
    exec(|conn| {
        let res: bool = conn.zadd(key, field, value)?;
        Ok(sciter::Value::from(res))
    })
}
/// 删除member
pub fn rem_z_set_member(key: String, field: String) -> sciter::Value {
    exec(|conn| {
        let res: bool = conn.zrem(key, field)?;
        Ok(sciter::Value::from(res))
    })
}
